Skip to content

Release: OpenCV 5 compatibility and crash/interruption hardening#459

Merged
JE-Chen merged 26 commits into
mainfrom
dev
Jul 23, 2026
Merged

Release: OpenCV 5 compatibility and crash/interruption hardening#459
JE-Chen merged 26 commits into
mainfrom
dev

Conversation

@JE-Chen

@JE-Chen JE-Chen commented Jul 23, 2026

Copy link
Copy Markdown
Member

Ship the dev backlog to main. The urgent part is OpenCV 5 support: je_open_cv==0.0.22 does not pin opencv-python, so the 5.0.0.93 release changed HoughLinesP output from (N, 1, 4) to (N, 4) and broke line/text-region detection for every fresh install off main. The fix already landed on dev (Restore line and text-region detection under OpenCV 5) but has not reached main, which is why CI on main-based PRs (e.g. #458) is red.

Also included: the crash and silent-interruption hardening pass from #457.

JE-Chen added 23 commits July 2, 2026 19:35
Move per-tab commands from in-tab buttons into a dynamic window-level
Actions menu so tabs stay minimal (inputs and results only). Core tabs
declare their actions at registration; feature tabs expose them via a
menu_actions() hook. Convert core tabs plus hotkeys, variables, secrets,
recording editor, and flow editor as the first batch.
Finish the menu-driven redesign started with the core tabs: every
registered feature tab now exposes its commands through menu_actions()
instead of in-tab buttons, so all tabs share the same minimal
inputs-and-results layout. Buttons that a window-level menu cannot
replace stay put: per-page browse buttons inside stacked trigger forms,
the visibility-toggled data-source browse button, and stateful
auto-refresh checkboxes. Button-text mutation and findChild retranslation
plumbing become status-label updates, with re-entry already guarded in
the handlers. Script Builder and Remote Desktop keep their interactive
panel layouts.
Every registered tab must surface its commands through the Actions
menu (registry actions or the menu_actions() hook); a missing hook
would silently strand a tab with no reachable commands now that the
in-tab buttons are gone.
The profiler enable button no longer swaps its text, so the key lost
its last reference.
Building the full tab set creates Qt widgets and native helper threads
whose teardown aborted the host interpreter long after the module
finished (CI: "Fatal Python error: Aborted" inside test_admin_client).
Run the probe in a child process and assert on its JSON report so the
rest of the headless suite stays deterministic.
HoughLinesP now returns (N, 4) instead of (N, 1, 4), so indexing the
middle axis unpacked scalars; reshape tolerates both layouts. MSER's
diversity pruning got strict enough to drop every region on flat
UI-style frames, so relax min_diversity progressively before reporting
that a frame has no text.
Redesign GUI around a menu-driven, low-button layout
New integrations get a small, lazy, typed entry point instead of the
eager historical top-level surface. Failed runs produce one atomic,
redacted autocontrol.failure-bundle/v1 ZIP (manifest, context, events,
log tail, optional screenshot/diagnostics) with best-effort collectors
so a broken screen grab cannot lose the bundle. codegen --failure-bundle
wraps generated pytest in automatic diagnostics; the secret redactor now
masks explicit key=value and bearer-token syntax regardless of entropy.
Publishing on every push to main made releases unauditable. Releases now
require a v* tag whose version must match pyproject, build provenance is
attested, and PyPI uses Trusted Publishing. quality.yml gains dependency
review, a coverage floor, and a mypy gate on the stable API surface; a
platform-smoke matrix exercises the stable API on all three OSes.
…exes

The docs lagged the code: Sphinx indexes stopped at v181 while v182-v223
existed, the Actions-menu redesign was undocumented outside WHATS_NEW,
and the project had no security policy, changelog, API lifecycle, or
honest platform-support statement. Adds all four, documents the menu-
driven GUI (v223 EN/Zh), syncs the three READMEs and WHATS_NEW files,
and records the Actions-menu tab contract in CLAUDE.md.
… mypy numpy, secret fixtures

- pytest-headless job lacked pytest-cov, so the --cov flags were unrecognized
- platform-smoke Linux runs need a virtual display (X11 connects at import)
- pin pypa/gh-action-pypi-publish to a full commit SHA (Sonar S7637 / Semgrep)
- skip numpy stubs under mypy (its type statements need 3.12+ to parse)
- assemble secret-shaped test values at runtime (Sonar S2068)
Full-project runtime-bug audit sweep with headless regression tests for
each fix. Groups of changes:

- Exceptions: reparent the family under AutoControlException; assertions
  still propagate under raise_on_error=False; typed exceptions no longer
  leak raw UnicodeError/ValueError past the JSON and HTML-report
  boundaries.
- Executor / flow: AC_parallel branches keep their own self-bound stock
  commands so nested execute stays scope-isolated; expect_poll matchers
  tolerate the not-ready None sentinel instead of crashing; malformed
  suite specs score an error instead of aborting the run.
- Platform: macOS cursor y-flip uses point-based (not pixel) display
  height on Retina; Interception window-click handles the button tuple;
  Wayland partial-coordinate scroll degrades gracefully; win32 input
  struct and wheel-scaling correctness.
- Network: USB/IP and command servers default to localhost; robust
  Content-Length and non-ASCII USB/IP busid handling; sqlite connections
  closed explicitly; atomic token writes.
- Vision / data: OpenCV writer release on stop; percent-safe sqlite URIs;
  data-source and JSON-schema hardening.
- GUI: off-thread callbacks marshalled via queued signals; broadened slot
  exception handling; identity-based Step equality; Actions-menu contract.
…ew-code findings

- test_r3_gui_main_window: importorskip qt_material so the headless job
  (PySide6 but no theme extra) skips instead of erroring collection.
- Clear Sonar new-code BUG/VULNERABILITY findings on the round-3 tests:
  slice access over index, pytest.approx for exact floats, dummy host
  URLs to https, and justified NOSONAR on reflexivity/side-effect asserts
  and the loopback-test TLS context.
- nosemgrep the two Codacy false positives (subprocess.TimeoutExpired is
  an exception class, not a subprocess call).
…st process

The WebRTC-panel import (pulls aiortc, absent in the headless job) and the
admin-console QThread teardown natively abort the shared pytest process under
the offscreen Qt platform on CI. The product paths are covered by the
subprocess-isolated full-widget build in test_actions_menu_gui. Skip these
three until they get the same subprocess isolation; the two stable marshaling
tests (LAN browse, presence roster) keep running.
…s finding

- relay._pipe: poll readability with select() + timeout instead of a bare
  blocking recv(). On Linux + CPython 3.14 a cross-thread dst.shutdown() no
  longer reliably wakes a recv() parked on the same socket, so _pair_and_pump's
  join() hung forever when one peer disconnected (test_pair_and_pump_exits_
  when_one_side_closes failed only on 3.14). Polling guarantees the thread
  re-checks the stop flag and exits.
- test_platform_backend_binding: slice access instead of events[0] index
  (clears the remaining Sonar new-code reliability finding).
…positive

- test_script_builder_param_preservation: importorskip PySide6.QtWidgets (not
  the bare PySide6 package) so it skips when Qt runtime libs like libEGL.so.1
  are absent — the shipped Docker image lacks them, so importing QtWidgets
  aborted collection of the whole in-image suite.
- test_platform_backend_binding: NOSONAR the slice assertion Sonar keeps
  flagging as S6466; a slice cannot raise IndexError, so it is a false positive.
…-docs-refresh

Stable API facade, failure bundles, tag-based releases, and full docs refresh
Add a WHATS_NEW.md entry and CHANGELOG Fixed/Changed notes for the runtime
audit fixes (Retina cursor, 3.14 relay hang, expect_poll/parallel robustness,
localhost-default USB/IP, typed-exception boundaries), and a synced What's New
summary in the English and zh-TW/zh-CN READMEs. Point the translated READMEs at
the existing WHATS_NEW.md (the WHATS_NEW_zh-*.md links were dead).
…hardening-notes

Docs: cross-platform reliability hardening notes
Fixes a class of defects where a long-running service dies silently or a whole
automation run aborts on an escaping exception:

- Coordinate coercion: a float x/y (computed/random var or JSON literal) no
  longer reaches an un-prototyped SetCursorPos / Xlib fake_input and raises
  ctypes.ArgumentError / struct.error that aborts the whole script; coerce to
  int in mouse_preprocess / set_mouse_position (+ Win32 cursor argtypes and a
  0-size-screen guard in _convert_position).
- Service-loop containment: the hotkey daemon (all platforms), Observer and
  PopupWatchdog poll loops, and the ChatOps command boundary widened to catch
  the failure types a normal script / user callback raises (AutoControlException,
  LookupError, StopIteration, ArithmeticError) instead of the thread dying and
  silently stopping every binding/rule.
- cv2.error from AC_match_template* is now contained as AutoControlScreenException
  rather than aborting the run.
- Server robustness: REST / Webhook / socket-command handlers get read timeouts
  (+ daemon_threads) so stalled clients can't pin worker threads; USB/IP prunes
  finished workers; the webhook fire lock is bounded and answers 503 busy rather
  than piling up handler threads; host_service and WebRTC input dispatch survive
  transient errors.

Test _FakeRequest gains a settimeout no-op to match a real socket.
…erruption-hardening

Prevent crashes and silent automation interruptions
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 805 complexity · 6 duplication

Metric Results
Complexity 805
Duplication 6

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

JE-Chen added 3 commits July 23, 2026 10:24
je_open_cv leaves opencv-python unpinned, so the OpenCV 5.0 release silently
changed cv2 return shapes and broke line/text-region detection for every fresh
install; an explicit `<6` bound stops the next major from doing the same.

Fold in the dependency bumps dependabot proposed against stale bases (pillow
12.3.0, pyobjc 12.2.1, ruff 0.15.22, pytest 9.1.1) and keep the versions the
workflows hardcode in sync with dev_requirements.txt. Pinning the CI tooling
installs also clears the SonarCloud githubactions:S8541/S8544 findings.
pytest 9.1 changed `importorskip`'s default `exc_type` from ImportError to
ModuleNotFoundError, so the container — which has PySide6 installed but no
libEGL — turned 16 previously skipped GUI modules into collection errors.
Ask for the old behaviour explicitly on the Qt guards.

Also move the workflow NOSONAR justifications onto the flagged lines; a
comment on the preceding line does not suppress githubactions:S8544.
…bumps

Bound the OpenCV major and refresh pinned dependency versions
@sonarqubecloud

Copy link
Copy Markdown

@JE-Chen
JE-Chen merged commit cbd755b into main Jul 23, 2026
47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant